/*
  reads and conditions every sensor: DHT22 humidity, LDR
  light, resistive soil moisture, battery voltage, HC-SR04 ultrasonic, and
  the hopper IR sensor. Applies filtering (EMA / median-of-3) and debounces
  the planting suitability decision so it doesn't flicker when a reading
  hovers near a threshold.
*/
#ifndef SENSOR_SUITE_H
#define SENSOR_SUITE_H

#include <Arduino.h>
#include <DHT.h>
#include "Config.h"
#include "Filters.h"
#include "StorageManager.h"

class SensorSuite {
public:
  void begin(StorageManager *storage);

  // Reads all sensors and updates filtered values + suitability debounce.
  void poll(unsigned long nowMs);

  float humidityPct() const   { return _humidity; }
  float lightPct() const      { return _lightFilter.get(); }
  float soilPct() const       { return _soilFilter.get(); }
  float batteryVoltage() const{ return _batteryFilter.get(); }
  float batteryPct() const;
  float distanceCm() const    { return _distanceFiltered; }

  // The hopper IR sensor detects a discrete event (a seed passing) rather
  // than an ambient condition, so unlike the environmental sensors above,
  // it is NOT cached on the poll cadence. The dispenser's plant-cycle state
  // machine calls this directly at the moment it needs to know whether a
  // seed is actually passing, which can be mid cycle, well between two
  // scheduled SENSING polls.
  bool readHopperLive() const { return analogRead(Pins::HOPPER_IR) < 500; }

  bool  isConditionSuitable() const { return _suitableLatched; }
  bool  isObstacleDetected() const  { return _distanceFiltered < Thresholds::WALL_DISTANCE_CM; }
  void calibrateSoilDry();
  void calibrateSoilWet();

private:
  DHT _dht{Pins::DHT_SENSOR, DHT22};
  StorageManager *_storage = nullptr;

  EMAFilter _lightFilter{0.25f};
  EMAFilter _soilFilter{0.15f};
  EMAFilter _batteryFilter{0.10f}; 
  Median3Filter _distanceMedian;

  float _humidity = 0;
  float _distanceFiltered = 400;

  bool  _suitableLatched = false;
  uint8_t _suitableStreak = 0;
  uint8_t _unsuitableStreak = 0;

  float readRawDistanceCm();
  float soilRawToPct(int raw) const;
};

#endif 
